#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
练习题 1 解答: 变量交换的多种实现方法
难度: ⭐
知识点: 变量赋值、元组解包、位运算、算术运算

本解答展示了Python中变量交换的4种经典方法，
每种方法都有其特点和适用场景。
"""

import time
import sys
from typing import Any, Tuple

def method1_tuple_unpacking(a: Any, b: Any) -> Tuple[Any, Any]:
    """
    方法1: 元组解包交换 (推荐)
    
    这是Python中最Pythonic的变量交换方式。
    利用了Python的元组打包和解包特性。
    
    优点:
    - 代码简洁优雅
    - 可读性强
    - 支持任意类型
    - 可以同时交换多个变量
    
    缺点:
    - 需要创建临时元组对象
    - 对于大对象可能有内存开销
    
    时间复杂度: O(1)
    空间复杂度: O(1)
    """
    print(f"方法1 - 交换前: a={a}, b={b}")
    
    # 核心代码：元组解包交换
    a, b = b, a
    
    print(f"方法1 - 交换后: a={a}, b={b}")
    return a, b

def method2_temporary_variable(a: Any, b: Any) -> Tuple[Any, Any]:
    """
    方法2: 临时变量交换 (传统方法)
    
    这是最传统和直观的变量交换方式，
    在大多数编程语言中都适用。
    
    优点:
    - 逻辑清晰易懂
    - 适用于所有编程语言
    - 不需要特殊语法支持
    - 内存使用明确
    
    缺点:
    - 需要额外的临时变量
    - 代码相对冗长
    
    时间复杂度: O(1)
    空间复杂度: O(1)
    """
    print(f"方法2 - 交换前: a={a}, b={b}")
    
    # 核心代码：使用临时变量
    temp = a
    a = b
    b = temp
    
    print(f"方法2 - 交换后: a={a}, b={b}")
    return a, b

def method3_arithmetic_operations(a: int, b: int) -> Tuple[int, int]:
    """
    方法3: 算术运算交换 (仅适用于数字)
    
    利用加法和减法的性质进行变量交换，
    不需要额外的存储空间。
    
    优点:
    - 不需要临时变量
    - 空间效率高
    - 展示数学技巧
    
    缺点:
    - 仅适用于数字类型
    - 可能导致整数溢出
    - 可读性较差
    - 浮点数可能有精度问题
    
    注意: 在实际项目中不推荐使用，仅作为算法技巧学习
    
    时间复杂度: O(1)
    空间复杂度: O(1)
    """
    print(f"方法3 - 交换前: a={a}, b={b}")
    
    # 检查输入类型
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError("算术运算交换仅适用于数字类型")
    
    # 核心代码：算术运算交换
    a = a + b  # a现在包含两个数的和
    b = a - b  # b现在等于原来的a
    a = a - b  # a现在等于原来的b
    
    print(f"方法3 - 交换后: a={a}, b={b}")
    return a, b

def method4_xor_operations(a: int, b: int) -> Tuple[int, int]:
    """
    方法4: 异或运算交换 (仅适用于整数)
    
    利用异或运算的性质进行变量交换，
    这是一个经典的位运算技巧。
    
    异或运算性质:
    - a ^ a = 0
    - a ^ 0 = a
    - 异或运算满足交换律和结合律
    
    优点:
    - 不需要临时变量
    - 空间效率高
    - 展示位运算技巧
    - 不会溢出
    
    缺点:
    - 仅适用于整数类型
    - 可读性较差
    - 如果a和b指向同一内存地址会出错
    
    注意: 在实际项目中不推荐使用，仅作为算法技巧学习
    
    时间复杂度: O(1)
    空间复杂度: O(1)
    """
    print(f"方法4 - 交换前: a={a}, b={b}")
    
    # 检查输入类型
    if not isinstance(a, int) or not isinstance(b, int):
        raise TypeError("异或运算交换仅适用于整数类型")
    
    # 检查是否为同一对象（避免自我异或导致清零）
    if a is b:
        print("警告: a和b指向同一对象，跳过异或交换")
        return a, b
    
    # 核心代码：异或运算交换
    a = a ^ b  # a现在包含a和b的异或结果
    b = a ^ b  # b现在等于原来的a (因为 (a^b)^b = a)
    a = a ^ b  # a现在等于原来的b (因为 (a^b)^a = b)
    
    print(f"方法4 - 交换后: a={a}, b={b}")
    return a, b

def demonstrate_all_methods():
    """
    演示所有变量交换方法
    """
    print("=== 变量交换方法演示 ===")
    
    # 测试数据
    test_cases = [
        (10, 20),           # 整数
        (3.14, 2.71),       # 浮点数
        ("hello", "world"),  # 字符串
        ([1, 2, 3], [4, 5, 6]),  # 列表
        ({"a": 1}, {"b": 2}),    # 字典
    ]
    
    for i, (a, b) in enumerate(test_cases, 1):
        print(f"\n--- 测试用例 {i}: {type(a).__name__} ---")
        original_a, original_b = a, b
        
        # 方法1: 元组解包（适用于所有类型）
        try:
            result_a, result_b = method1_tuple_unpacking(a, b)
            assert result_a == original_b and result_b == original_a
            print("✓ 方法1测试通过")
        except Exception as e:
            print(f"✗ 方法1测试失败: {e}")
        
        # 方法2: 临时变量（适用于所有类型）
        try:
            result_a, result_b = method2_temporary_variable(a, b)
            assert result_a == original_b and result_b == original_a
            print("✓ 方法2测试通过")
        except Exception as e:
            print(f"✗ 方法2测试失败: {e}")
        
        # 方法3: 算术运算（仅适用于数字）
        if isinstance(a, (int, float)) and isinstance(b, (int, float)):
            try:
                result_a, result_b = method3_arithmetic_operations(a, b)
                assert result_a == original_b and result_b == original_a
                print("✓ 方法3测试通过")
            except Exception as e:
                print(f"✗ 方法3测试失败: {e}")
        else:
            print("- 方法3跳过（不适用于此类型）")
        
        # 方法4: 异或运算（仅适用于整数）
        if isinstance(a, int) and isinstance(b, int):
            try:
                result_a, result_b = method4_xor_operations(a, b)
                assert result_a == original_b and result_b == original_a
                print("✓ 方法4测试通过")
            except Exception as e:
                print(f"✗ 方法4测试失败: {e}")
        else:
            print("- 方法4跳过（不适用于此类型）")

def performance_comparison():
    """
    性能比较测试
    """
    print("\n=== 性能比较测试 ===")
    
    # 测试参数
    test_iterations = 1000000
    test_a, test_b = 12345, 67890
    
    # 方法1: 元组解包
    start_time = time.perf_counter()
    for _ in range(test_iterations):
        a, b = test_a, test_b
        a, b = b, a
    method1_time = time.perf_counter() - start_time
    
    # 方法2: 临时变量
    start_time = time.perf_counter()
    for _ in range(test_iterations):
        a, b = test_a, test_b
        temp = a
        a = b
        b = temp
    method2_time = time.perf_counter() - start_time
    
    # 方法3: 算术运算
    start_time = time.perf_counter()
    for _ in range(test_iterations):
        a, b = test_a, test_b
        a = a + b
        b = a - b
        a = a - b
    method3_time = time.perf_counter() - start_time
    
    # 方法4: 异或运算
    start_time = time.perf_counter()
    for _ in range(test_iterations):
        a, b = test_a, test_b
        a = a ^ b
        b = a ^ b
        a = a ^ b
    method4_time = time.perf_counter() - start_time
    
    # 输出结果
    print(f"测试次数: {test_iterations:,}")
    print(f"方法1 (元组解包): {method1_time:.6f}秒")
    print(f"方法2 (临时变量): {method2_time:.6f}秒")
    print(f"方法3 (算术运算): {method3_time:.6f}秒")
    print(f"方法4 (异或运算): {method4_time:.6f}秒")
    
    # 找出最快的方法
    times = {
        "元组解包": method1_time,
        "临时变量": method2_time,
        "算术运算": method3_time,
        "异或运算": method4_time
    }
    fastest = min(times, key=times.get)
    print(f"\n最快方法: {fastest} ({times[fastest]:.6f}秒)")

def memory_usage_analysis():
    """
    内存使用分析
    """
    print("\n=== 内存使用分析 ===")
    
    # 创建大对象进行测试
    large_list_a = list(range(1000000))
    large_list_b = list(range(1000000, 2000000))
    
    print(f"大对象A大小: {sys.getsizeof(large_list_a):,} 字节")
    print(f"大对象B大小: {sys.getsizeof(large_list_b):,} 字节")
    
    # 测试元组解包的内存使用
    print("\n测试元组解包交换大对象...")
    start_time = time.perf_counter()
    large_list_a, large_list_b = large_list_b, large_list_a
    tuple_time = time.perf_counter() - start_time
    print(f"元组解包交换时间: {tuple_time:.6f}秒")
    
    # 测试临时变量的内存使用
    print("\n测试临时变量交换大对象...")
    start_time = time.perf_counter()
    temp = large_list_a
    large_list_a = large_list_b
    large_list_b = temp
    temp_time = time.perf_counter() - start_time
    print(f"临时变量交换时间: {temp_time:.6f}秒")
    
    print("\n结论: 对于大对象，两种方法的性能差异很小")
    print("元组解包更简洁，临时变量更明确")

def edge_cases_testing():
    """
    边界情况测试
    """
    print("\n=== 边界情况测试 ===")
    
    # 测试相同值
    print("\n--- 测试相同值 ---")
    a, b = 42, 42
    print(f"交换前: a={a}, b={b}")
    a, b = b, a
    print(f"交换后: a={a}, b={b}")
    
    # 测试None值
    print("\n--- 测试None值 ---")
    a, b = None, "something"
    print(f"交换前: a={a}, b={b}")
    a, b = b, a
    print(f"交换后: a={a}, b={b}")
    
    # 测试空容器
    print("\n--- 测试空容器 ---")
    a, b = [], {}
    print(f"交换前: a={a}, b={b}")
    a, b = b, a
    print(f"交换后: a={a}, b={b}")
    
    # 测试异或运算的特殊情况
    print("\n--- 测试异或运算特殊情况 ---")
    
    # 相同值的异或
    a = b = 100
    print(f"相同值异或前: a={a}, b={b}")
    try:
        # 这会导致两个值都变成0，因为 x ^ x = 0
        if a is not b:  # 检查是否为不同对象
            a = a ^ b
            b = a ^ b
            a = a ^ b
        else:
            print("跳过异或操作（相同对象）")
        print(f"相同值异或后: a={a}, b={b}")
    except Exception as e:
        print(f"异或操作失败: {e}")

def multiple_variable_swap():
    """
    多变量交换演示
    """
    print("\n=== 多变量交换演示 ===")
    
    # 三变量循环交换
    print("\n--- 三变量循环交换 ---")
    a, b, c = 1, 2, 3
    print(f"交换前: a={a}, b={b}, c={c}")
    
    # 方法1: 元组解包（推荐）
    a, b, c = b, c, a
    print(f"循环交换后: a={a}, b={b}, c={c}")
    
    # 四变量交换
    print("\n--- 四变量两两交换 ---")
    a, b, c, d = "A", "B", "C", "D"
    print(f"交换前: a={a}, b={b}, c={c}, d={d}")
    
    # 同时交换多对变量
    (a, b), (c, d) = (b, a), (d, c)
    print(f"两两交换后: a={a}, b={b}, c={c}, d={d}")
    
    # 列表元素交换
    print("\n--- 列表元素交换 ---")
    numbers = [1, 2, 3, 4, 5]
    print(f"交换前: {numbers}")
    
    # 交换第一个和最后一个元素
    numbers[0], numbers[-1] = numbers[-1], numbers[0]
    print(f"首尾交换后: {numbers}")
    
    # 反转整个列表
    numbers = [1, 2, 3, 4, 5]
    for i in range(len(numbers) // 2):
        numbers[i], numbers[-(i+1)] = numbers[-(i+1)], numbers[i]
    print(f"完全反转后: {numbers}")

def best_practices_and_recommendations():
    """
    最佳实践和建议
    """
    print("\n=== 最佳实践和建议 ===")
    
    recommendations = [
        "1. 优先使用元组解包 (a, b = b, a)",
        "   - 最Pythonic的方式",
        "   - 代码简洁清晰",
        "   - 支持所有数据类型",
        "",
        "2. 临时变量适用于教学和其他语言",
        "   - 逻辑清晰易懂",
        "   - 适合初学者理解",
        "   - 跨语言通用",
        "",
        "3. 避免使用算术和异或运算交换",
        "   - 仅适用于特定类型",
        "   - 可读性差",
        "   - 容易出错",
        "   - 仅作为算法技巧学习",
        "",
        "4. 多变量交换使用元组解包",
        "   - 可以同时交换多个变量",
        "   - 语法简洁优雅",
        "   - 性能良好",
        "",
        "5. 注意边界情况",
        "   - 相同对象的交换",
        "   - None值的处理",
        "   - 大对象的内存考虑"
    ]
    
    for recommendation in recommendations:
        print(recommendation)

if __name__ == "__main__":
    # 运行所有演示
    demonstrate_all_methods()
    performance_comparison()
    memory_usage_analysis()
    edge_cases_testing()
    multiple_variable_swap()
    best_practices_and_recommendations()
    
    print("\n=== 总结 ===")
    print("变量交换是编程中的基础操作，Python提供了优雅的元组解包语法。")
    print("理解不同方法的原理有助于深入理解Python的特性和计算机科学基础。")
    print("在实际开发中，推荐使用元组解包方式进行变量交换。")
